package fingerprint;

/**
 * Created by guolanqing on 16/11/3.
 * for test usage!
 */
import grade.MostNum;
import scanner.WaveFileReader;

import java.io.IOException;
import java.sql.*;
import java.util.*;

import static fingerprint.FFT.fft;

public class Test {
    static final String url = "jdbc:mysql://127.0.0.1:3306/fingerprint?user=root&autoReconnect=true&useSSL=false&useUnicode=true&characterEncoding=utf-8";
    static final String user = "root";
    static final String password = "*******";

    public static void main(String[] args) throws IOException {


        long startTime = System.currentTimeMillis();   //get the start time
        String songName = "G.E.M.邓紫棋 - 你不是真正的快乐_01.wav";
        String file = "data/wav_part_3/" + songName;

        //Start
        System.out.println("Read Into:  " + songName);
        WaveFileReader id_x = new WaveFileReader(file);
        ArrayList<double[]> slices = new ArrayList<double[]>();

        if (!id_x.isSuccess())
            return;
        //
        double[] idx = id_x.getFinalData();
        //song_idx是一个fingerprint对象
        FingerPrint song_idx = new FingerPrint(1);
        //计算出划分的块数
        int number = id_x.getDataLen() / FFT.WINDOW_SIZE;
        double[] ret = new double[FFT.WINDOW_SIZE];

        //利用傅里叶算法将时域信息转换成频域信息
        for (int i = 0; i < number; i++) {
            double[] slice = new double[FFT.WINDOW_SIZE];
            for (int j = 0; j < FFT.WINDOW_SIZE; j++) {
                slice[j] = idx[FFT.WINDOW_SIZE * i + j];

            }
            ret = FFT.fft(slice);
            //提取出频率的N个最大值
            song_idx.append(fft(slice));
            slices.add(ret);
        }
        //使用组合哈希算法，进行f1、f2、dt的获取
        //hashes是一个傅里叶list
        ArrayList<ShazamHash> hashes = new ArrayList<ShazamHash>();
        hashes = song_idx.combineHash();
        ArrayList<ArrayList<Integer>> data = new ArrayList<ArrayList<Integer>>();
        int size = getSongCounts();
        for (int i = 0; i < size; i++) {
            ArrayList<Integer> i_list = new ArrayList<Integer>();
            data.add(i_list);
        }
        //Start
        System.out.println("Enquiry:  " + songName);

        //generate repeated data map
        Grade(hashes, data);


        MostNum most = new MostNum();
        Map map = new HashMap();

        for (int i = 0; i < size; i++) {
            int max = most.method3(data.get(i));
            map.put(i + 1, max);
        }


        map = sortByValue(map);
        Set<Integer> key = map.keySet();
        List<Integer> finalID = new ArrayList<Integer>();
        for (Iterator it = key.iterator(); it.hasNext(); ) {
            Integer s = (Integer) it.next();
            finalID.add(s);
        }

        //        输出结果
        PrintResult(finalID);
        //获取结束时间
        long endTime = System.currentTimeMillis();
        System.out.println("查询总耗时： " + (endTime - startTime) / 1000.0 + "s");
    }

    //查询数据库寻找匹配程度最高的五首歌曲
    public static void Grade(ArrayList<ShazamHash> m_hashes, ArrayList<ArrayList<Integer>> data) {

        Connection con = null;
        Statement st = null;
        ResultSet rs = null;
        PreparedStatement pstm = null;

        try {
            con = DriverManager.getConnection(url, user, password);
            st = con.createStatement();

            //构造sql语句

            String sql = "SELECT song_id,offset FROM song_finger WHERE finger_id=?";


            PreparedStatement ps = con.prepareStatement(sql);


            for (int i = 0; i < m_hashes.size(); i++) {

                int offset = m_hashes.get(i).offset;
                ps.setInt(1, m_hashes.get(i).finger_id);

                rs = ps.executeQuery();
                while (rs.next()) {
                    int id = rs.getInt("song_id");
                    int minus = rs.getInt("offset") - offset;
                    data.get(id - 1).add(minus);
                }
            }
            st.close();
            con.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public static int getSongCounts() {

        Connection con = null;
        Statement st = null;
        ResultSet rs = null;
        int count = 0;

        try {
            con = DriverManager.getConnection(url, user, password);
            st = con.createStatement();

            ResultSet rs3 = st.executeQuery("SELECT  count(*) AS song FROM song;");
            while (rs3.next()) {
                count = rs3.getInt(1);
            }
            st.close();
            con.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return count;
    }

    public static List<String> PrintResult(List<Integer> list) {

        Connection con = null;
        PreparedStatement st = null;
        ResultSet rs = null;
        List<String> songs = new ArrayList<String>();

        try {
            con = DriverManager.getConnection(url, user, password);
            //构造sql语句
            String sql = "SELECT name FROM song WHERE song_id = ?";
            PreparedStatement ps = con.prepareStatement(sql);
            for (int i = 0; i < 5; i++) {
                ps.setInt(1, list.get(i));
                rs = ps.executeQuery();
                /*
                 * there was an error, but it has been fixed now
                 * when you already prepared the statement in connection.prepareStatement(query);
                 * then why to pass the query again in selectUser.executeQuery(query);
                 */
                if (rs.next()) {
                    songs.add(rs.getString("name"));
                }
                rs.close();
            }

            System.out.println("we found five possible songs for you：");
            int i = 0;
            for (String name : songs) {
                System.out.println("No." + (++i) + "：  " + name);
            }
            con.close();

        } catch (SQLException e) {
            e.printStackTrace();
        }
        return songs;
    }

    //sort numbers in the order of value
    public static Map sortByValue(Map map) {
        List list = new LinkedList(map.entrySet());
        Collections.sort(list, new Comparator() {
            // 将链表按照值得从小到大进行排序
            public int compare(Object o1, Object o2) {
                return ((Comparable) ((Map.Entry) (o2)).getValue()).compareTo(((Map.Entry) (o1)).getValue());
            }
        });
        Map result = new LinkedHashMap();
        for (Iterator it = list.iterator(); it.hasNext(); ) {
            Map.Entry entry = (Map.Entry) it.next();
            result.put(entry.getKey(), entry.getValue());
        }
        return result;
    }


}
